package m3f.backprojection;

import org.jblas.DoubleMatrix;

import m3f.data.MultimodalCachedLoader;
import m3f.data.MultimodalDataSet;
import m3f.data.SingleDataSet;
import m3f.io.DenseMatrixWriter;
import m3f.matrix.Minibatch;

public class Combiner {
	
	private static DoubleMatrix P;

	public static void writeCombinedRepresentation(
			MultimodalCachedLoader trainingSet, MultimodalDataSet testSet,
			SingleDataSet p, double alpha, double beta, String outputTraining, String outputTest) {
		P = p.fullBatch().matrix();
		
		System.out.println("Writing the backprojected representation for training data");
		trainingSet.reset(false);
		trainingSet.setMinibatchSize(1000);
		DenseMatrixWriter writer = new DenseMatrixWriter(outputTraining);
		
		ConcurrentCombinedMatrixWriter ccmw = new ConcurrentCombinedMatrixWriter(trainingSet, writer, P, alpha);
		Thread thread = new Thread(ccmw);
		thread.start();
		try{
			thread.join();
		}catch(InterruptedException ie){
			ie.printStackTrace();
		}
		writer.close();
		
		writer = new DenseMatrixWriter(outputTest);
		DenseMatrixWriter.writeMatrix(
				Combiner.backprojection(testSet.maxVisualBatch(), testSet.maxTextBatch(), P, beta),
				outputTest,
				true);
	}

	public static DoubleMatrix backprojection(Minibatch v, Minibatch h,
			DoubleMatrix P1, double alpha) {
		return P1.mmul(h.matrix()).muli(alpha).addi(v.matrix().muli(1 - alpha));
		/*
		// Solve for b first
		// P*(lambda*I + P'P + Q'Q)h = P*P'*b
		System.out.println("P(" + P1.rows + "," + P1.columns + ") Q(" + Q1.rows + "," + Q1.columns + ")");
		DoubleMatrix S = P1.transpose().mmul(P1);
		S.addi( Q1.transpose().mmul(Q1).muli(lambda) );
		S = P1.mmul(S);
		DoubleMatrix b = Solve.solve(P1.mmul(P1.transpose()), S.mmul(h.matrix()));
		// Combine later:
		// alpha*b + (1 - alpha)*v
		return b.muli(alpha).addi( v.matrix().muli(1-alpha) );
		*/
	}

}
